using System.Collections;
using NHibernate.Engine;
using NHibernate.UserTypes;
using NHibernate.Collection;
using NHibernate.Persister.Collection;

namespace AiFrame.InterfaceLib.Data.Patterns
{
    /// <summary>
    /// Represents a list collection that fires events when the collection's contents have 
    /// changed.
    /// </summary>
    /// <typeparam name="T">Type of item to be stored in the list.</typeparam>
    public class HibernateObservableList<T> : BaseObservableList<T>, IObservableList<T>, IUserCollectionType
    {
        public new void Add(T item)
        {
            base.Add(item);
            this.OnItemAdded(item);
        }
        
        public new void Clear()
        {
            base.Clear();
            this.OnItemsReset();
        }

        public new void Insert(int index, T item)
        {
            base.Insert(index, item);
            this.OnItemAdded(item);
        }

        public new bool Remove(T item)
        {
            int index = this.IndexOf(item);

            bool result = base.Remove(item);
            this.OnItemRemoved(item, index);

            return result;
        }

        public new void RemoveAt(int index)
        {
            T item = this[index];

            base.RemoveAt(index);
            this.OnItemRemoved(item, index);
        }


        #region IUserCollectionType Members

        public bool Contains(object collection, object entity)
        {
            return ((IObservableList<T>)collection).Contains((T)entity);
        }

        public new IEnumerable GetElements(object collection)
        {
            return (IEnumerable)collection;
        }

        public object IndexOf(object collection, object entity)
        {
            return ((IObservableList<T>)collection).IndexOf((T)entity);
        }

        public object Instantiate()
        {
            return new HibernateObservableList<T>();
        }

        public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
        {
            return new PersistentGenericObservableBag<T>(session);
        }

        public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, System.Collections.IDictionary copyCache, ISessionImplementor session)
        {
            IObservableList<T> result = (IObservableList<T>)target;

            result.Clear();
            foreach (object item in ((IEnumerable)original))
            {
                result.Add((T)item);
            }
            this.OnItemsReset();

            return result;
        }

        public object Instantiate(int anticipatedSize)
        {
//            base.Capacity = anticipatedSize;
            return new HibernateObservableList<T>();
//            throw new System.NotImplementedException();
        }

        public IPersistentCollection Wrap(ISessionImplementor session, object collection)
        {
            return new PersistentGenericObservableBag<T>(session, (HibernateObservableList<T>)collection);
        }

        #endregion

        #region Implementation of IObservableList<T>

        public void Replace(T obj)
        {
            this.OnItemReplace(obj);
        }

        #endregion
    }
}